import React, { useContext, useReducer } from 'react';
import { Row, Col, Menu, Icon, Dropdown, Button, Input } from 'antd';
import { useDeepCompareEffect } from 'ahooks';
import get from 'lodash/get';
import last from 'lodash/last';
import isEqual from 'lodash/isEqual';
import NodePathSelect from '../NodePathSelect';
import Rule from '../Rule';
import {
  ASSERTS,
  CONDITIONS,
  PATH_TYPE,
  ASSERT_ALL,
  ASSERT_ONE,
  FIRST_ELEMENT_ACCESSOR_TYPE,
} from '../../settings';
import Context from '@/pages/Transformer/components/SourcePanel/context';

// 判断是不是该添加`路径`了，因为业务需求，必须保证`路径`和`条件`交替添加
function judge(value) {
  if (!Array.isArray(value) || isEqual(value, [])) {
    return true;
  }

  if (get(last(value), 'type') === PATH_TYPE) {
    return false;
  }

  if (ASSERTS.map(k => k.value).includes(get(last(value), 'type'))) {
    return true;
  }

  if (get(last(value), 'type') === FIRST_ELEMENT_ACCESSOR_TYPE) {
    return true;
  }

  throw new Error('`judge`');
}

const defaultValue = [
  {
    type: PATH_TYPE,
    path: null,
  },
];

const initialState = {
  value: defaultValue,
};

function reducer(state, action) {
  const { type, payload } = action;

  if (type === 'sync_props') {
    return {
      ...state,
      ...payload,
    };
  }

  if (type === 'change_value') {
    const { index, item, notify } = payload;

    const newData = [...state.value];
    newData[index] = item;

    notify(newData);

    return {
      ...state,
      value: newData,
    };
  }

  if (type === 'add_condition') {
    const newData = [...state.value];

    newData.push(payload);

    return {
      ...state,
      value: newData,
    };
  }

  if (type === 'delete_last_one') {
    const newData = [...state.value];

    newData.pop();

    return {
      ...state,
      value: newData,
    };
  }

  if (type === 'add_path') {
    const newData = [...state.value];

    newData.push({ type: PATH_TYPE });

    return {
      ...state,
      value: newData,
    };
  }

  if (type === 'add_first_element_accessor') {
    const newData = [...state.value];

    newData.push({ type: FIRST_ELEMENT_ACCESSOR_TYPE });

    return {
      ...state,
      value: newData,
    };
  }

  throw new Error();
}

function Mapper({
  value,
  treeData,
  disabled = false,
  readOnly = false,
  onChange,
  mode = 'select',
  style,
}) {
  const [state, dispatch] = useReducer(reducer, initialState);

  useDeepCompareEffect(() => {
    const data = {};

    if (Array.isArray(value)) {
      data.value = value.length === 0 ? defaultValue : value;
    }

    if (Object.keys(data).length > 0) {
      dispatch({ type: 'sync_props', payload: data });
    }
  }, [value]);

  const menu = (
    <Menu
      onClick={e =>
        dispatch({
          type: 'add_condition',
          payload: {
            type: ASSERT_ONE,
            condition: {
              type: e.key,
            },
          },
        })
      }
    >
      {CONDITIONS.map(k => (
        <Menu.Item key={k.value}>{k.title}</Menu.Item>
      ))}
    </Menu>
  );

  const isTurnForNodePathSelect = judge(state.value);

  function notify(newValue) {
    if (typeof onChange === 'function' && !isEqual(value, newValue)) {
      onChange(newValue);
    }
  }

  return (
    <div style={style}>
      {state.value.map((k, i) => (
        <Row
          style={{ marginTop: i === 0 ? 0 : 8, marginBottom: i === state.value.length - 1 ? 0 : 8 }}
          // eslint-disable-next-line react/no-array-index-key
          key={i}
        >
          <Col span={24}>
            {get(k, 'type') === PATH_TYPE && (
              <NodePathSelect
                treeData={treeData}
                mode={mode}
                onChange={data => {
                  dispatch({
                    type: 'change_value',
                    payload: { index: i, item: { type: PATH_TYPE, path: data }, notify },
                  });
                }}
                value={k.path}
                disabled={disabled}
                readOnly={readOnly}
              />
            )}
            {(get(k, 'type') === ASSERT_ALL || get(k, 'type') === ASSERT_ONE) && (
              <Rule
                treeData={treeData}
                value={k}
                mode={mode}
                asserts={ASSERTS}
                disabled={disabled}
                readOnly={readOnly}
                onChange={data => {
                  dispatch({ type: 'change_value', payload: { index: i, item: data, notify } });
                }}
              />
            )}
            {get(k, 'type') === FIRST_ELEMENT_ACCESSOR_TYPE && (
              <Input value="取第一个元素" disabled />
            )}
          </Col>
        </Row>
      ))}
      <Row className="margin-top">
        {isTurnForNodePathSelect ? (
          <Col span={12} style={{ paddingRight: 4 }}>
            <Button
              type="default"
              block
              className="text-primary"
              onClick={() => {
                dispatch({
                  type: 'add_path',
                });

                const newData = [...state.value];

                newData.push({ type: PATH_TYPE });
                notify(newData);
              }}
            >
              添加路径
            </Button>
          </Col>
        ) : (
          <>
            <Col span={6} style={{ paddingRight: 4 }}>
              <Button
                type="default"
                block
                className="text-primary"
                onClick={() => {
                  dispatch({
                    type: 'add_first_element_accessor',
                  });

                  const newData = [...state.value];

                  newData.push({ type: FIRST_ELEMENT_ACCESSOR_TYPE });
                  notify(newData);
                }}
              >
                取第一个元素
              </Button>
            </Col>
            <Col span={6} style={{ paddingLeft: 4, paddingRight: 4 }}>
              <Dropdown overlay={menu} placement="topCenter">
                <Button type="default" block className="text-primary">
                  添加过滤条件 <Icon type="down" />
                </Button>
              </Dropdown>
            </Col>
          </>
        )}

        <Col span={12} style={{ paddingLeft: 4 }}>
          <Button
            disabled={state.value.length < 2}
            type="default"
            block
            className="text-danger"
            onClick={() => {
              dispatch({
                type: 'delete_last_one',
              });

              const newData = [...state.value];

              newData.pop();
              notify(newData);
            }}
          >
            删除最后一条
          </Button>
        </Col>
      </Row>
    </div>
  );
}

export default Mapper;
